#include "Scene.h"

int FloorFlag = 1;

// 构造 ——场景初始化（宽，高，玩家）
Scene::Scene(int width, int height, Player &p) : width(width), height(height), player(p), shop(p)
{
    // 中间的位置留给商店
    shop.GetLocation().Setx(width / 2);
    shop.GetLocation().Sety(height / 2);

    Ladder &ladder = Ladder::GetLadder();
    // 最后一个位置留给梯子
    ladder.GetLocation().Setx(width - 1);
    ladder.GetLocation().Sety(height - 1);

    Map.resize(height);
    for (int i = 0; i < height; i++)
    {
        for (int j = 0; j < width; j++)
        {
            // 向第i行添加元素
            Map[i].push_back("🧱");
        }
    }
    // 把场景的边界设置给玩家
    p.SetMaxWidth(width);
    p.SetMaxHeight(height);

    // 先初始化容器再初始化怪物
    // 初始化随机容器
    InitRandContainer();
    // 初始化怪兽
    IntialMonsters();
    // 初始化宝箱
    IntialBoxex();
}

// 秀一下场景
void Scene::show()
{
    // 先将所有位置初始化
    for (int i = 0; i < height; i++)
    {
        for (int j = 0; j < width; j++)
        {
            Map[i][j] = ("🧱");
        }
    }
    // 把地图上的一个位置变成玩家的位置
    Map[player.GetLocation().Gety()][player.GetLocation().Getx()] = player.GetSymbol();
    // 把地图上的一个位置变成商店的位置
    Map[shop.GetLocation().Gety()][shop.GetLocation().Getx()] = shop.GetSymbol();
    // 把地图上的一个位置变成梯子的位置
    Ladder &ladder = Ladder::GetLadder();
    Map[ladder.GetLocation().Gety()][ladder.GetLocation().Getx()] = ladder.GetSymbol();

    // 显示怪兽
    for (auto m : Monsters)
    {
        // 如果怪兽还活着，就显示
        if (m.GetHP() > 0)
            Map[m.GetLocation().Gety()][m.GetLocation().Getx()] = m.GetSymbol();
    }
    // 显示宝箱
    for (auto &b : Boxes)
    {
        if (b.BoxFlag == 0)
            Map[b.GetLocation().Gety()][b.GetLocation().Getx()] = b.GetSymbol();
    }

    for (int i = 0; i < height; i++)
    {
        for (int j = 0; j < width; j++)
        {
            std::cout << Map[i][j];
        }
        std::cout << std::endl;
    }
}

// 进入商店
void Scene::BuyInShop()
{
    if (player.GetLocation() == shop.GetLocation())
    {
        shop.show();
    }
}

// 判断和怪兽是否在同一位置
Monster *Scene::IsMonsInSamePlace()
{
    // 遍历Monsters容器中的每一个元素
    for (auto &m : Monsters)
    {
        if (m.GetHP() > 0 && player.GetLocation() == m.GetLocation())
            return &m;
    }
    return nullptr;
}

// 判断和宝箱是否在同一位置
Box *Scene::IsBoxInSamePlace()
{
    // 遍历Boxes容器中的每一个元素
    for (auto &b : Boxes)
    {
        if (player.GetLocation() == b.GetLocation())
            return &b;
    }
    return nullptr;
}

// 判断和梯子是否在同一位置
Ladder *Scene::IsLadderInSamePlace()
{
    Ladder &ladder = Ladder::GetLadder();
    if ((FloorFlag == 1 && player.GetLocation() == ladder.GetLocation() && player.GetLevel() >= 10) ||
        (FloorFlag == 2 && player.GetLocation() == ladder.GetLocation() && player.GetLevel() >= 30) ||
        (FloorFlag == 3 && player.GetLocation() == ladder.GetLocation() && player.GetLevel() >= 50))
    {
        FloorFlag++;
        if (FloorFlag <= 3)
        {
            std::cout << "🎊恭喜你成功进入第" << FloorFlag << "层🎊" << std::endl;
            player.SetFloor(FloorFlag);
            sleep(1);
            return &ladder;
        }
        else
        {
            std::cout << "🎉恭喜你通关啦！祝你生活愉快~🎉" << std::endl;
            sleep(1);
            exit(-1);
        }
    }
    return nullptr;
}

// 初始化所有的怪兽
void Scene::IntialMonsters()
{
    if (FloorFlag == 1)
    {
        // 骷髅兵
        Monsters.push_back(Bone(GetRandomPlaces()));
        Monsters.push_back(Bone(GetRandomPlaces()));
        Monsters.push_back(Bone(GetRandomPlaces()));
        Monsters.push_back(Bone(GetRandomPlaces()));
        Monsters.push_back(Bone(GetRandomPlaces()));
        Monsters.push_back(Bone(GetRandomPlaces()));
        Monsters.push_back(Bone(GetRandomPlaces()));
        // 霸王龙
        Monsters.push_back(Dinosaur(GetRandomPlaces()));
        Monsters.push_back(Dinosaur(GetRandomPlaces()));
        Monsters.push_back(Dinosaur(GetRandomPlaces()));
        Monsters.push_back(Dinosaur(GetRandomPlaces()));
        Monsters.push_back(Dinosaur(GetRandomPlaces()));
        // 食人魔
        Monsters.push_back(Orge(GetRandomPlaces()));
    }
    else if (FloorFlag == 2)
    {
        // 小马喽
        Monsters.push_back(Monkey(GetRandomPlaces()));
        Monsters.push_back(Monkey(GetRandomPlaces()));
        Monsters.push_back(Monkey(GetRandomPlaces()));
        Monsters.push_back(Monkey(GetRandomPlaces()));
        Monsters.push_back(Monkey(GetRandomPlaces()));
        Monsters.push_back(Monkey(GetRandomPlaces()));
        Monsters.push_back(Monkey(GetRandomPlaces()));
        // 猛犸兽
        Monsters.push_back(Lizard(GetRandomPlaces()));
        Monsters.push_back(Lizard(GetRandomPlaces()));
        Monsters.push_back(Lizard(GetRandomPlaces()));
        Monsters.push_back(Lizard(GetRandomPlaces()));
        Monsters.push_back(Lizard(GetRandomPlaces()));
        // 狼王
        Monsters.push_back(Wolf(GetRandomPlaces()));
    }
    else if (FloorFlag == 3)
    {
        // 人鱼怪
        Monsters.push_back(Fish(GetRandomPlaces()));
        Monsters.push_back(Fish(GetRandomPlaces()));
        Monsters.push_back(Fish(GetRandomPlaces()));
        Monsters.push_back(Fish(GetRandomPlaces()));
        Monsters.push_back(Fish(GetRandomPlaces()));
        Monsters.push_back(Fish(GetRandomPlaces()));
        Monsters.push_back(Fish(GetRandomPlaces()));
        // 僵尸
        Monsters.push_back(Zombie(GetRandomPlaces()));
        Monsters.push_back(Zombie(GetRandomPlaces()));
        Monsters.push_back(Zombie(GetRandomPlaces()));
        Monsters.push_back(Zombie(GetRandomPlaces()));
        Monsters.push_back(Zombie(GetRandomPlaces()));
        // 外星人
        Monsters.push_back(ET(GetRandomPlaces()));
    } 
}

// 初始化所有的宝箱
void Scene::IntialBoxex()
{
    Boxes.push_back(Box(GetRandomPlaces()));
    Boxes.push_back(Box(GetRandomPlaces()));
    Boxes.push_back(Box(GetRandomPlaces()));
}

// 初始化随机容器
void Scene::InitRandContainer()
{
    // 把除玩家之外的所有位置放入容器，进行洗牌
    // 首先，往这个容器塞所有的坐标
    for (int i = 0; i < height; i++)
    {
        for (int j = 0; j < width; j++)
        {
            // 如果是玩家位置就不放进去
            if (player.GetLocation().Getx() == j && player.GetLocation().Gety() == i)
                continue;
            // 如果是商店位置就不放进去
            if (j == width / 2 && i == height / 2)
                continue;
            // 如果是第一层梯子位置就不放进去
            if (j == width - 1 && i == height - 1)
                continue;
            // 如果是第二层梯子位置就不放进去
            if (j == 0 && i == 0)
                continue;
            // 往容器里面塞对象
            RandPlaces.push_back(Point(j, i));
        }
    }
    // 构建随机种子
    srand(time(nullptr));
    // 洗牌（这样得出来的坐标是不会重合的）
    std::random_shuffle(RandPlaces.begin(), RandPlaces.end());
}

// 获取随机坐标
Point Scene::GetRandomPlaces()
{
    // 拿容器里的最后一个位置
    Point p = *(RandPlaces.end() - 1);
    // 从容器的末尾移除最后一个元素
    RandPlaces.pop_back();
    return p;
}

// 将怪物信息存入容器
std::vector<std::string> Scene::GetMonsterInfo() 
{
    std::vector<std::string> monsterInfo;
    for (int i = 0; i < Monsters.size(); i++)
    {
        monsterInfo.push_back(Monsters[i].GetInfo());
    }
    return monsterInfo;
}

// 将宝箱信息存入容器
std::vector<std::string> Scene::GetBoxInfo() 
{
    std::vector<std::string> boxInfo;
    for (const auto &box : Boxes)
    {
        boxInfo.push_back(box.GetInfo());
    }
    return boxInfo;
}


// 写入怪物信息
void Scene::WriteInMonsterInfo(std::string &fileName)
{
    auto monsterInfo = GetMonsterInfo();
    std::string monsterFilePath = "./存档/" + player.GetName() + "/" + fileName + "/Monster.txt";
    FileTools::WriteLine(monsterFilePath, monsterInfo);
}

// 写入宝箱信息
void Scene::WriteInBoxInfo(std::string &fileName)
{
    auto boxInfo = GetBoxInfo();
    std::string boxFilePath = "./存档/" + player.GetName() + "/" + fileName + "/Box.txt";
    FileTools::WriteLine(boxFilePath, boxInfo); 
}

// 按下v存档或删档
void Scene::Save(std::string &fileName)
{
    if (player.Move() == true)
    {
        std::cout << "请选择你要进行的操作：1存档 2删除存档" << std::endl;
        int num = 0;
        std::cin >> num;
        if (num == 1)
        {
            std::cout << "正在存档..." << std::endl;
            sleep(1);
            WriteInMonsterInfo(fileName);
            WriteInBoxInfo(fileName);
            player.WriteInPlayerInfo(fileName);
            player.WriteInBagInfo(fileName);
            std::cout << "存档成功" << std::endl;
            sleep(1);
        }
        else if (num == 2)
        {
            std::cout << "正在删档..." << std::endl;
            sleep(1);
            player.RemoveFile(fileName);
            std::cout << "删档成功" << std::endl;
            sleep(1);
        }  
    }
}

// 读取角色信息
void Scene::ReadPlayer(std::string &fileName)
{
    std::vector<std::string> vec = FileTools::ReadLine("./存档/" + player.GetName() + "/" + fileName + "/" + "Player.txt");
    for (auto &Line : vec)
    {
        StdMyString s(Line.c_str());
        MyStringList l = s.split(" ");

        player.SetName(l[0].c_str());
        player.SetSymbol(l[1].c_str());
        player.SetAttack((int)l[2]);
        player.SetHP((int)l[3]);
        player.SetDefend((int)l[4]);
        player.GetLocation().Setx((int)l[5]);
        player.GetLocation().Sety((int)l[6]);
        player.SetGold((int)l[7]);
        player.SetDiamond((int)l[8]);
        player.SetExp((int)l[9]);
        player.SetLevel((int)l[10]);
        player.SetAttrPoint((int)l[11]);
        player.SetPower((int)l[12]);
        player.SetDodge((int)l[13]);
        player.SetFloor((int)l[14]);
    }
}

// 读取背包信息
void Scene::ReadBag(std::string &fileName)
{
    player.ReadBagInfo(fileName);
}

// 读取怪兽信息
void Scene::ReadMonster(std::string &fileName)
{
    std::vector<std::string> vec = FileTools::ReadLine("./存档/" + player.GetName() + "/" + fileName + "/" + "Monster.txt");
    for (int i = 0; i < vec.size(); i++)
    {
        StdMyString s(vec[i].c_str());
        MyStringList l = s.split(" ");

        Monsters[i].SetSymbol(l[0].c_str());
        Monsters[i].SetName(l[1].c_str());
        Monsters[i].GetLocation().Setx((int)l[2]);
        Monsters[i].GetLocation().Sety((int)l[3]);
        Monsters[i].SetHP((int)l[4]);
        Monsters[i].SetAttack((int)l[5]);
        Monsters[i].SetDefend((int)l[6]);
        Monsters[i].SetExp((int)l[7]);
        Monsters[i].SetGold((int)l[8]);
        Monsters[i].SetDiamond((int)l[9]);
        Monsters[i].SetPower((int)l[10]);
        Monsters[i].SetDodge((int)l[11]);
    }
}

// 读取宝箱信息
void Scene::ReadBox(std::string &fileName)
{
    std::vector<std::string> vec = FileTools::ReadLine("./存档/" + player.GetName() + "/" + fileName + "/" + "Box.txt");
    for (int i = 0; i < vec.size(); i++)
    {
        StdMyString s(vec[i].c_str());
        MyStringList l = s.split(" ");

        Boxes[i].SetSymbol(l[0].c_str());
        Boxes[i].GetLocation().Setx((int)l[1]);
        Boxes[i].GetLocation().Sety((int)l[2]);
        Boxes[i].BoxFlag = (int)l[3];
    }
}

// 战阶
void Battle(Player &p, Monster &m)
{
    while (1)
    {
        BattleInterface(p, m);
        sleep(1);
        int PlayerAttack = 0;
        if (IsDodge(m))
        {
            std::cout << "⚡可恶,怪兽闪避了你的攻击!" << std::endl;
            sleep(1);
        }
        else
        {
            if (IsPower(p))
            {
                std::cout << "💫你对怪兽发生了灵魂暴击——biu!" << std::endl;
                sleep(1);
                PlayerAttack = std::max(p.GetAttack() - m.GetDefend(), 0) * 2;
            }
            else
            {
                // 玩家攻击伤害 = | 玩家攻击力 - 怪兽防御力 |
                PlayerAttack = std::max(p.GetAttack() - m.GetDefend(), 0);
            }
        }

        // 刷新怪兽血量（怪兽血量 - 玩家攻击伤害）
        m.SetHP(std::max(m.GetHP() - PlayerAttack, 0));
        std::cout << p.GetName() << "对" << m.GetName() << "造成了|" << PlayerAttack << "|点伤害\n";
        sleep(1);
        // 如果怪兽被打死了
        if (m.GetHP() <= 0)
        {
            // 怪兽重置血量（0）
            m.SetHP(0);
            // 回到战阶界面
            BattleInterface(p, m);
            std::cout << "你战胜了|" << m.GetName() << "|!🤏\n";
            sleep(1);
            std::cout << "获得经验值|" << m.GetExp() << "|\n";
            sleep(1);
            std::cout << "获得金币|" << m.GetGold() << "|\n";
            sleep(1);
            std::cout << "获得钻石|" << m.GetDiamond() << "|" << std::endl;
            sleep(1);
            // 玩家重置经验值（玩家经验值 + 怪兽经验值）
            p.SetExp(p.GetExp() + m.GetExp());
            // 升级
            p.LevelUp();
            // 玩家重置金币（玩家金币 + 怪兽金币）
            p.SetGold(p.GetGold() + m.GetGold());
            // 玩家重置钻石（玩家钻石 + 怪兽钻石）
            p.SetDiamond(p.GetDiamond() + m.GetDiamond());
            sleep(1);
            return;
        }

        // 如果怪兽没被打死，轮到怪兽反击
        int MonsterAttack = 0;
        if (IsDodge(p))
        {
            std::cout << "🌟你躲过怪兽的一击,太棒了!" << std::endl;
            sleep(1);
        }
        else
        {
            if (IsPower(m))
            {
                std::cout << "☄️怪兽对你发生了猛兽暴击——嗷呜!" << std::endl;
                sleep(1);
                MonsterAttack = std::max(m.GetAttack() - p.GetDefend(), 0) * 2;
            }
            else
            {
                // 怪兽攻击伤害 = | 怪兽攻击力 - 玩家防御力 |
                MonsterAttack = std::max(m.GetAttack() - p.GetDefend(), 0);
            }
        }

        // 刷新玩家血量（玩家血量 - 怪兽攻击伤害）
        p.SetHP(std::max(p.GetHP() - MonsterAttack, 0));
        std::cout << m.GetName() << "对|" << p.GetName() << "|造成了|" << MonsterAttack << "|点伤害\n";
        sleep(1);
        // 如果玩家被打死
        if (p.GetHP() <= 0)
        {
            // 重置玩家血量
            p.SetHP(0);
            // 回到战阶界面
            BattleInterface(p, m);
            std::cout << "胜败乃兵家常事，大侠请重新来过!💪\n";
            sleep(1);
            while (1)
            {
                std::cout << "是否花费15钻石复活?🤑(y/n)" << std::endl;
                char c = 0;
                std::cin >> c;
                if (c == 'y' || c == 'Y')
                {
                    if (p.GetDiamond() >= 15)
                    {
                        p.SetDiamond(p.GetDiamond() - 15);
                        p.SetHP(std::min(m.GetHP(), p.MaxHP));
                        return;
                    }
                    else
                    {
                        std::cout << "钻石不够哦，请重新开始吧！" << std::endl;
                        sleep(1);
                        // 关闭程序
                        exit(-1);
                    }
                }
                exit(-1);
            }
        }
    }
}

// 战阶界面
void BattleInterface(Player &p, Monster &m)
{
    // 先清屏
    system("clear");
    std::cout << "玩家姓名:|" << p.GetName() << "|" << "   VS   ";
    std::cout << "怪兽姓名:|" << m.GetName() << "|" << std::endl;
    std::cout << "血量❤️:|" << p.GetHP() << "|" << "       ";
    std::cout << "   血量❤️:|" << m.GetHP() << "|" << std::endl;
    std::cout << "攻击力🗡️:|" << p.GetAttack() << "|" << "       ";
    std::cout << "  攻击力🗡️:|" << m.GetAttack() << "|" << std::endl;
    std::cout << "防御力🛡️:|" << p.GetDefend() << "|" << "       ";
    std::cout << "  防御力🛡️:|" << m.GetDefend() << "|" << std::endl;
}

// 第二层场景构造
Scene2::Scene2(int width, int height, Player &p) : Scene(WIDTH, HEIGHT, p)
{
    // 中间的位置留给商店
    shop.GetLocation().Setx(width / 2);
    shop.GetLocation().Sety(height / 2);

    // 第一个位置留给梯子
    Ladder &ladder = Ladder::GetLadder();
    ladder.GetLocation().Setx(0);
    ladder.GetLocation().Sety(0);

    Map.resize(height);
    for (int i = 0; i < height; i++)
    {
        for (int j = 0; j < width; j++)
        {
            // 向第i行添加元素
            Map[i].push_back("🟪");
        }
    }
    // 把场景的边界设置给玩家
    p.SetMaxWidth(width);
    p.SetMaxHeight(height);

    // 清空第一层的怪兽列表
    Monsters.clear();
    // 清空第一层的宝箱列表
    Boxes.clear();
    // 清空第一层的随机坐标容器
    RandPlaces.clear();

    // 先初始化容器再初始化怪物
    // 初始化随机容器
    InitRandContainer();
    // 初始化怪兽
    IntialMonsters();
    // 初始化宝箱
    IntialBoxex();
}

// 秀一下第二层场景
void Scene2::show2()
{
    // 先将所有位置初始化
    for (int i = 0; i < height; i++)
    {
        for (int j = 0; j < width; j++)
        {
            Map[i][j] = ("🟪");
        }
    }
    // 把地图上的一个位置变成玩家的位置
    Map[player.GetLocation().Gety()][player.GetLocation().Getx()] = player.GetSymbol();
    // 把地图上的一个位置变成商店的位置
    Map[shop.GetLocation().Gety()][shop.GetLocation().Getx()] = shop.GetSymbol();
    // 把地图上的一个位置变成梯子的位置
    Ladder &ladder = Ladder::GetLadder();
    Map[ladder.GetLocation().Gety()][ladder.GetLocation().Getx()] = ladder.GetSymbol();

    // 显示怪兽
    for (auto m : Monsters)
    {
        // 如果怪兽还活着，就显示
        if (m.GetHP() > 0)
            Map[m.GetLocation().Gety()][m.GetLocation().Getx()] = m.GetSymbol();
    }
    // 显示宝箱
    for (auto &b : Boxes)
    {
        if (b.BoxFlag == 0)
            Map[b.GetLocation().Gety()][b.GetLocation().Getx()] = b.GetSymbol();
    }

    for (int i = 0; i < height; i++)
    {
        for (int j = 0; j < width; j++)
        {
            std::cout << Map[i][j];
        }
        std::cout << std::endl;
    }
}

// 第三层场景构造
Scene3::Scene3(int width, int height, Player &p) : Scene(WIDTH, HEIGHT, p)
{
    // 中间的位置留给商店
    shop.GetLocation().Setx(width / 2);
    shop.GetLocation().Sety(height / 2);

    // 最后一个位置留给梯子
    Ladder &ladder = Ladder::GetLadder();
    ladder.GetLocation().Setx(width - 1);
    ladder.GetLocation().Sety(height - 1);

    Map.resize(height);
    for (int i = 0; i < height; i++)
    {
        for (int j = 0; j < width; j++)
        {
            // 向第i行添加元素
            Map[i].push_back("🟨");
        }
    }
    // 把场景的边界设置给玩家
    p.SetMaxWidth(width);
    p.SetMaxHeight(height);

    // 清空第二层的怪兽列表
    Monsters.clear();
    // 清空第二层的宝箱列表
    Boxes.clear();
    // 清空第二层的随机坐标容器
    RandPlaces.clear();

    // 先初始化容器再初始化怪物
    // 初始化随机容器
    InitRandContainer();
    // 初始化怪兽
    IntialMonsters();
    // 初始化宝箱
    IntialBoxex();
}

// 秀一下第三层场景
void Scene3::show3()
{
    // 先将所有位置初始化
    for (int i = 0; i < height; i++)
    {
        for (int j = 0; j < width; j++)
        {
            Map[i][j] = ("🟨");
        }
    }
    // 把地图上的一个位置变成玩家的位置
    Map[player.GetLocation().Gety()][player.GetLocation().Getx()] = player.GetSymbol();
    // 把地图上的一个位置变成商店的位置
    Map[shop.GetLocation().Gety()][shop.GetLocation().Getx()] = shop.GetSymbol();
    // 把地图上的一个位置变成梯子的位置
    Ladder &ladder = Ladder::GetLadder();
    Map[ladder.GetLocation().Gety()][ladder.GetLocation().Getx()] = ladder.GetSymbol();

    // 显示怪兽
    for (auto m : Monsters)
    {
        // 如果怪兽还活着，就显示
        if (m.GetHP() > 0)
            Map[m.GetLocation().Gety()][m.GetLocation().Getx()] = m.GetSymbol();
    }
    // 显示宝箱
    for (auto &b : Boxes)
    {
        if (b.BoxFlag == 0)
            Map[b.GetLocation().Gety()][b.GetLocation().Getx()] = b.GetSymbol();
    }

    for (int i = 0; i < height; i++)
    {
        for (int j = 0; j < width; j++)
        {
            std::cout << Map[i][j];
        }
        std::cout << std::endl;
    }
}